package main

import (
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"sync"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"
	"github.com/gorilla/websocket"
)

type Crowd struct {
	CrowdId  int64
	UserId   int64
	JoinTime string
	Status   string
}

func main() {

	http.HandleFunc("/joinCrowd", JoinChat)
	http.HandleFunc("/crowdChat", CrowdChat)
	http.ListenAndServe(":8080", nil)
}

func JoinChat(w http.ResponseWriter, r *http.Request) {
	userId := r.FormValue("user_id")
	crowdId := r.FormValue("crowd_id")
	userIdInt, _ := strconv.Atoi(userId)
	crowdIdInt, _ := strconv.Atoi(crowdId)
	fmt.Println(userId, crowdId)
	err := JoinCrowd(&Crowd{
		CrowdId:  int64(crowdIdInt),
		UserId:   int64(userIdInt),
		JoinTime: time.Now().Format(time.DateTime),
		Status:   "0",
	})
	if err != nil {
		fmt.Println(err)
		fmt.Fprintln(w, "加入群失败")
	}
	fmt.Fprintln(w, "加群成功")
}

func GetCrowdMember(Id int64) ([]Crowd, error) {
	var c []Crowd

	err := engine.Where("crowd_id=?", Id).Find(&c)
	if err != nil {
		fmt.Println(err)
		return []Crowd{}, err
	}
	return c, nil
}

var engine *xorm.Engine

func JoinCrowd(c *Crowd) error {
	_, err := engine.Insert(c)
	if err != nil {
		return err
	}
	return nil
}

//昭阳留 迷彩 简微 乐瑶 李小允 方圆 妍颜 向晨 cc 罗永和 尉然

func init() {
	driverName := "mysql"
	dataSourceName := "root:root@tcp(127.0.0.1:3306)/user"
	var err error
	engine, err = xorm.NewEngine(driverName, dataSourceName)
	if err != nil {
		fmt.Println(err)
		return
	}
	engine.ShowSQL(true)
}

// Node websocket 协议& 管道
type Node struct {
	Coon *websocket.Conn
	Ch   chan []byte
}

var MyMap map[int64]*Node = make(map[int64]*Node, 0)

var wg sync.WaitGroup

func InCrowd(Id, userid int64) error {
	var c Crowd
	res, err := engine.Where("crowd_id=? and user_id=?", Id, userid).Get(&c)
	if err != nil {
		fmt.Println(err)
		return err
	}
	if !res {
		return errors.New("user is not in Group")
	}
	return nil
}

func CrowdChat(w http.ResponseWriter, r *http.Request) {
	userId := r.FormValue("user_id")
	crowdId := r.FormValue("crowd_id")

	crowdIdInt, _ := strconv.Atoi(crowdId)
	userIdIdInt, _ := strconv.Atoi(userId)

	err := InCrowd(int64(crowdIdInt), int64(userIdIdInt))
	if err != nil {
		fmt.Fprintln(w, err)

		return
	}
	c, err := GetCrowdMember(int64(crowdIdInt))
	if err != nil {
		fmt.Fprintln(w, err)
		return
	}
	fmt.Println(c)
	var id []int64
	for _, v := range c {
		id = append(id, v.UserId)
	}

	//将http 协议 升级为 websocket 协议
	coon, err := (&websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}).Upgrade(w, r, nil)
	if err != nil {
		fmt.Fprintln(w, err)
	}

	//实例化 结构体
	n := &Node{
		Coon: coon,
		Ch:   make(chan []byte, 50),
	}

	MyMap[int64(userIdIdInt)] = n
	fmt.Println(id)
	fmt.Println(MyMap)

	wg.Add(2)
	go SendMsg(n)
	go ReceiveMsg(n, id, int64(userIdIdInt))
	wg.Wait()

}

// SendMsg 发布信息
func SendMsg(n *Node) {
	defer wg.Done()
	for {
		select {
		case msg := <-n.Ch:
			fmt.Println(string(msg))
			err := n.Coon.WriteMessage(websocket.TextMessage, msg)
			if err != nil {
				fmt.Println(err)
				return
			}
		}
	}
}

// ReceiveMsg 接受信息
func ReceiveMsg(n *Node, ids []int64, id int64) {
	defer wg.Done()
	for {
		_, msg, err := n.Coon.ReadMessage()
		if err != nil {
			fmt.Println(err)
			return
		}
		for _, c := range ids {
			node, ok := MyMap[c]
			if ok {
				if c != id {
					fmt.Println("Recover 找到 Node 对象")
					//向管道中写入信息
					node.Ch <- msg
				}
			} else {
				fmt.Println("不在该群里")
			}
		}
	}
}
